﻿using Comm.PublicClass;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Wasion.HHU.Services;
using Wasion.HHU.Views;
using WsProtocol.IEC62056;
using WsProtocol.IEC62056.DLL;
using WsProtocol.IEC62056MDL;

namespace Wasion.HHU.ViewModels
{
    public class Meter
    {
        
        internal readonly object receivedSync = new object();
        internal int receivedSize;
        internal byte[] m_Received = null;
        internal int lastPosition;

        public string MeterNumber { get; set; }
        public string MeterAddress { get; set; }
        public bool IsConnected { get; set; } = false;

        public List<TestMeter> MeterLst = new List<TestMeter>();
        private List<TestMeter> tmpMeterLst = new List<TestMeter>();
        private FunMeterMulti funMeter;  //与表通信操作对象
        private SecurityPolicy SecurityOption = SecurityPolicy.需认证加密;
        private NextFramePostedDelegate NextFramePosted;
        public event EventHandler<MsgInfoEventArgs> showInfo;
        public event EventHandler<MsgInfoEventArgs> ConnCompleted;

        CancellationTokenSource tokenSource = new CancellationTokenSource();

        public Meter()
        {
            funMeter = new FunMeterMulti();
            NextFramePosted = new NextFramePostedDelegate(DoAfterRead);
            PtlBaseUIProConsts.ShowComminfo += DoChangeOrderStatus;

            m_Received = new byte[1000];
            lastPosition = 0;

        }

        public async Task<bool> ConnectAsync()
        {
            //BluetoothService.WriteStringAsync("test");
            StartReviceData();

            string errinfo = string.Empty;

            tmpMeterLst.Clear();
            var t = Task.Run(() =>
            {
                return funMeter.DoConnect(MeterLst, tmpMeterLst, SecurityOption, NextFramePosted, ref errinfo);
            });
            int rs = await t;

            if (rs < 0)
            {
                IsConnected = false;
                ConnCompleted?.Invoke(this, new MsgInfoEventArgs("-1", errinfo));
                return false;
            }
            else
            {
                IsConnected = true;
                ConnCompleted?.Invoke(this, new MsgInfoEventArgs("0", errinfo));
                return true;
            }
            
        }

        public void ReadData(List<TestMeter> testMeters ,NextFramePostedDelegate nextFramePostedDelegate)
        {
            funMeter.RWOneDataFromObAttr(testMeters, EnuFrameType.I, ClientApduSel.GETRequest, GetRRMode.GetNormal.ToString(), true, nextFramePostedDelegate);
        }

        public void SetData(List<TestMeter> testMeters, NextFramePostedDelegate nextFramePostedDelegate)
        {
            if (testMeters[0].ObAttrLst[0].AttrMth == AttrType.方法)
                funMeter.RWOneDataFromObAttr(testMeters, EnuFrameType.I, ClientApduSel.ActionRequest, ActionRRMode.ActionNormal.ToString(), true, nextFramePostedDelegate);
            else
                funMeter.RWOneDataFromObAttr(testMeters, EnuFrameType.I, ClientApduSel.SETRequest, SetRRMode.SetNormal.ToString(), true, nextFramePostedDelegate);
        }

        private void StartReviceData()
        {
            var cancellationToken = tokenSource.Token;
            Task t1 = Task.Factory.StartNew(async () =>
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    await Task.Delay(100);
                    //await dataReader.LoadAsync(1);
                    var a = Shell.BluetoothService.LoadAsync(1);
                    if (cancellationToken.IsCancellationRequested)
                    {
                        a.Cancel();
                    }
                    await a;

                    int count = 0;
                    byte[] buff = null;
                    while ((count = Shell.BluetoothService.UnconsumedBufferLength) != 0)
                    {
                        //totalCount += count;
                        buff = new byte[count];
                        //m_base.Read(buff, 0, count); 
                        Shell.BluetoothService.ReadBytes(buff);

                        AppendData(buff, 0, count);

                        string errinfo = "";
                        string outorder = MyConvert.ByteArrayToHexString(m_Received);
                        var order = this.MeterLst[0].currorder;
                        if (order != null)
                        {
                            if (order.GetCorrectFrame != null)
                            {
                                outorder = order.GetCorrectFrame(ref outorder, ref errinfo);
                                if (string.IsNullOrEmpty(outorder))
                                {
                                    //order.Fail(true, errinfo);
                                    continue;
                                }
                            }
                        }
                        else
                        {
                            order = this.tmpMeterLst[0].currorder;
                            if (order != null)
                            {
                                if (order.GetCorrectFrame != null)
                                {
                                    outorder = order.GetCorrectFrame(ref outorder, ref errinfo);
                                    if (string.IsNullOrEmpty(outorder))
                                    {
                                        //order.Fail(true, errinfo);
                                        continue;
                                    }
                                }
                            }
                            else
                            {
                                continue;
                            }
                        }

                        int nFound = receivedSize;
                        //Convert bytes to object.
                        byte[] tmp = new byte[nFound];
                        lock (receivedSync)
                        {
                            Array.Copy(m_Received, tmp, nFound);
                        }
                        receivedSize -= nFound;
                        if (receivedSize < 0)
                        {
                            receivedSize = 0;
                        }
                        if (receivedSize != 0)
                        {
                            lock (receivedSync)
                            {
                                Array.Copy(m_Received, nFound, m_Received, 0, receivedSize);
                            }
                        }
                        else
                        {
                            lastPosition = 0;
                            m_Received = new byte[1000];
                        }

                        //order.RecDelay = 1;
                        order.recstr = outorder;

                        order.SendFlag = CommConst.CommFlag.CommReceived;
                        order.Msgflag = CommConst.CommFlag.CommReceived;
                        if (order.DoAnalysis != null)
                            order.DoAnalysis(order);
                    }
                }

            }, cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Default);
        }

        public void AppendData(byte[] data, int index, int count)
        {
            lock (receivedSync)
            {
                //Alocate new buffer.
                if (receivedSize + count > m_Received.Length)
                {
                    byte[] tmp = new byte[2 * m_Received.Length];
                    Array.Copy(m_Received, 0, tmp, 0, receivedSize);
                    m_Received = tmp;
                }
                Array.Copy(data, index, m_Received, receivedSize, count);
                receivedSize += count - index;
            }
        }

        public async Task<bool> DisConnectAsync()
        {
            string errinfo = string.Empty;
            var t = Task.Run(() =>
            {
                return funMeter.Disconnect(MeterLst, ref errinfo);
            });
            int rs = await t;

            if (rs < 0)
            {
                IsConnected = true;
                //ConnCompleted?.Invoke(this, new MsgInfoEventArgs("-1", errinfo));
                return false;
            }
            else
            {
                IsConnected = false;
                ConnCompleted?.Invoke(this, new MsgInfoEventArgs("-2", errinfo));
                return true;
            }
        }

        public async Task<string> ReadAsync(uint length)
        {
            return await Shell.BluetoothService.ReadStringAsync(length);
        }

        public async Task WriteAsync(string value)
        {
            var b = MyConvert.HexStringToByteArray(value);
            await Shell.BluetoothService.WriteByteAsync(b);
        }

        public async Task<byte[]> ReadByteAsync(uint length)
        {
            return await Shell.BluetoothService.ReadByteAsync(length);
        }

        public async Task WriteAsync(byte[] value)
        {
            await Shell.BluetoothService.WriteByteAsync(value);
        }

        private void DoAfterRead(object testMeter, object anaPtl, ClientApduSel rwflag, string rwtype, int doflag, string errinfo)
        {
            //AfterReadhandler.Invoke()
            try
            {
                Analysis62056.TProtocol62056 orderptl = (Analysis62056.TProtocol62056)anaPtl;
                TestMeter resmeter = (TestMeter)testMeter;
                List<CosemObject> OILst = orderptl.ptlformat.Apdu.OIList;
                if (OILst == null)
                    return;

                for (int i = 0; i < OILst.Count; i++)
                {
                    CosemObject oiobj = OILst[i];
                    if (orderptl.ptlformat.Apdu.rwflag == ClientApduSel.ConnectRequest
                        || orderptl.ptlformat.Apdu.rwflag == ClientApduSel.DLReleaseRequest)
                    {

                        if (doflag > 0)
                        {
                            showInfo?.Invoke(this, new MsgInfoEventArgs(oiobj.AmName + "  " + "成功"));
                            Debug.WriteLine(oiobj.AmName + "  " + "成功");
                            //tsbInfo.Text = oiobj.AmName + "  " + "成功";
                            //meterPage.NotifyUser(oiobj.AmName + "  " + "成功", Views.NotifyType.StatusMessage);
                            if (oiobj.result != null && oiobj.result != "0")
                            {
                                showInfo?.Invoke(this, new MsgInfoEventArgs(oiobj.AmName + "  " + oiobj.result));
                                Debug.WriteLine(oiobj.AmName + "  " + oiobj.result);
                                //tsbInfo.Text = oiobj.AmName + "  " + oiobj.result;
                                //meterPage.NotifyUser(oiobj.AmName + "  " + oiobj.result, Views.NotifyType.StatusMessage);

                                resmeter.ErrInfo = oiobj.result;
                            }
                        }
                        else
                        {
                            showInfo?.Invoke(this, new MsgInfoEventArgs(oiobj.AmName + "  " + errinfo));
                            Debug.WriteLine(oiobj.AmName + "  " + errinfo);
                            //tsbInfo.Text = oiobj.AmName + "  " + errinfo;
                            //meterPage.NotifyUser(oiobj.AmName + "  " + errinfo, Views.NotifyType.StatusMessage);
                            resmeter.ErrInfo = errinfo;
                        }
                    }
                }
            }
            finally
            {

            }
        }

        private void DoChangeOrderStatus(CommConst.TOrdertype aorder)
        {

            int SNO = aorder.MeterSNo;

            switch (aorder.Msgflag)
            {
                case CommConst.CommFlag.CommSending:  //发送中
                    try
                    {
                        string sendinfo = PubFunction.SplitStr(aorder.order) + "[" + aorder.OrderName;
                        if (aorder.dotimes > 0)
                            sendinfo += "(第" + aorder.dotimes + "次)";
                        sendinfo += "]";
                        //commshow.AddSend(string.Format("<{0}>" + clsLan.GetLan("发:") + "{1}\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), sendinfo));
                        showInfo?.Invoke(this, new MsgInfoEventArgs(string.Format("<{0}>" + "发:" + "{1}"+ Environment.NewLine, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), sendinfo)));

                        if (!string.IsNullOrEmpty(aorder.orderinfo) && aorder.orderno == 0)
                        {
                            //commshow.AddSend(aorder.orderinfo + "\r\n");
                            showInfo?.Invoke(this, new MsgInfoEventArgs(aorder.orderinfo));
                        }
                    }
                    catch
                    { }
                    break;
                case CommConst.CommFlag.CommSendFail: //发送失败
                    try
                    {
                        string sendinfo = aorder.errorinfo;

                        //commshow.AddSend(string.Format("<{0}>" + clsLan.GetLan("发:") + "{1}\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), sendinfo));
                        showInfo?.Invoke(this, new MsgInfoEventArgs(string.Format("<{0}>" + "发:" + "{1}"+ Environment.NewLine, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), sendinfo)));
                    }
                    catch
                    { }
                    break;
                case CommConst.CommFlag.CommReceived:  //收到返回
                case CommConst.CommFlag.CommFail:   //失败
                    try
                    {
                        string recstr = aorder.recstr;
                        string errinfo = string.Empty;
                        if (aorder.Msgflag == CommConst.CommFlag.CommFail) //指令失败了
                        {
                            if (aorder.SendFlag == CommConst.CommFlag.CommNone) //指令没发出
                                return;

                            if (string.IsNullOrEmpty(aorder.recstr)) //未收到合法的返回帧
                                recstr = aorder.errrecstr;  //取收到的错误返回帧
                            else
                                return;
                            errinfo = aorder.errorinfo;//错误信息
                        }
                        else
                        {
                            if (string.IsNullOrEmpty(recstr))
                                return;
                        }

                        recstr = PubFunction.SplitStr(recstr) + "[" + aorder.OrderName + "(" + aorder.RecDelay + "毫秒" + ")]";
                        if (!string.IsNullOrEmpty(errinfo))
                            recstr += ":"
                                    + errinfo;
                        recstr = recstr.Replace("\0", "");
                        //commshow.AddReceive(string.Format("<{0}>" + clsLan.GetLan("收:") + "{1}\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), recstr));
                        showInfo?.Invoke(this, new MsgInfoEventArgs(string.Format("<{0}>" + "收:" + "{1}"+ Environment.NewLine, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), recstr)));

                        if (aorder.Msgflag == CommConst.CommFlag.CommFail)
                        {
                            if (aorder.waitreturn && aorder.DoAfterAnalysis != null && !string.IsNullOrEmpty(aorder.orderinfo))
                            {
                                //commshow.AddReceive(aorder.orderinfo + "\r\n");
                                showInfo?.Invoke(this, new MsgInfoEventArgs(aorder.orderinfo));
                            }

                        }
                    }
                    catch
                    { }
                    break;
                case CommConst.CommFlag.CommSuccess:
                    if (aorder.waitreturn && aorder.DoAfterAnalysis != null && !string.IsNullOrEmpty(aorder.orderinfo))
                    {
                        //commshow.AddReceive(aorder.orderinfo + "\r\n");
                        showInfo?.Invoke(this, new MsgInfoEventArgs(aorder.orderinfo));
                    }
                    break;
            };

        }
    }

    public class MsgInfoEventArgs : EventArgs
    {
        public string Code { get; set; }
        /// <summary>
        /// Message
        /// </summary>
        public string Msg { get; set; }
        public MsgInfoEventArgs(string _msg)
        {
            this.Code = "";
            this.Msg = _msg;
        }
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="ClassGrade"></param>
        /// <param name="ClassName"></param>
        public MsgInfoEventArgs(string _code,string _msg)
        {
            this.Code = _code;
            this.Msg = _msg;
        }
    }
}
